package com.ruoyi.sycs.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.base.domain.vo.SyTypeVo;
import com.ruoyi.base.service.ISyTypeService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.syrw.domain.BsDataReport;
import com.ruoyi.syrw.mapper.BsDataReportMapper;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.impl.SysDictDataServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.formula.atp.Switch;
import org.springframework.stereotype.Service;
import com.ruoyi.sycs.domain.bo.BsRuleBo;
import com.ruoyi.sycs.domain.vo.BsRuleVo;
import com.ruoyi.sycs.domain.BsRule;
import com.ruoyi.sycs.mapper.BsRuleMapper;
import com.ruoyi.sycs.service.IBsRuleService;

import java.time.LocalDate;
import java.util.*;

/**
 * 编号规则设置Service业务层处理
 *
 * @author zyb
 * @date 2024-04-24
 */
@RequiredArgsConstructor
@Service
public class BsRuleServiceImpl implements IBsRuleService {

    private final BsRuleMapper baseMapper;

    private final ISysDictDataService iSysDictDataService;

    private final ISyTypeService iSyTypeService;

    private final BsDataReportMapper bsDataReportMapper;

    /**
     * 查询编号规则设置
     */
    @Override
    public BsRuleVo queryById(Long ruleId){
        return baseMapper.selectVoById(ruleId);
    }

    /**
     * 查询编号规则设置列表
     */
    @Override
    public TableDataInfo<BsRuleVo> queryPageList(BsRuleBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<BsRule> lqw = buildQueryWrapper(bo);
        Page<BsRuleVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询编号规则设置列表
     */
    @Override
    public List<BsRuleVo> queryList(BsRuleBo bo) {
        LambdaQueryWrapper<BsRule> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<BsRule> buildQueryWrapper(BsRuleBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<BsRule> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getDeptId() != null, BsRule::getDeptId, bo.getDeptId());
        lqw.eq(bo.getSyTypeId() != null, BsRule::getSyTypeId, bo.getSyTypeId());
        lqw.like(StringUtils.isNotBlank(bo.getRuleName()), BsRule::getRuleName, bo.getRuleName());
        lqw.eq(StringUtils.isNotBlank(bo.getFgf()), BsRule::getFgf, bo.getFgf());
        lqw.eq(StringUtils.isNotBlank(bo.getP1Type()), BsRule::getP1Type, bo.getP1Type());
        lqw.eq(StringUtils.isNotBlank(bo.getP1Content()), BsRule::getP1Content, bo.getP1Content());
        lqw.eq(StringUtils.isNotBlank(bo.getP2Type()), BsRule::getP2Type, bo.getP2Type());
        lqw.eq(StringUtils.isNotBlank(bo.getP2Content()), BsRule::getP2Content, bo.getP2Content());
        lqw.eq(StringUtils.isNotBlank(bo.getP3Type()), BsRule::getP3Type, bo.getP3Type());
        lqw.eq(StringUtils.isNotBlank(bo.getP3Content()), BsRule::getP3Content, bo.getP3Content());
        lqw.eq(StringUtils.isNotBlank(bo.getP4Type()), BsRule::getP4Type, bo.getP4Type());
        lqw.eq(StringUtils.isNotBlank(bo.getP4Content()), BsRule::getP4Content, bo.getP4Content());
        lqw.eq(StringUtils.isNotBlank(bo.getP5Type()), BsRule::getP5Type, bo.getP5Type());
        lqw.eq(StringUtils.isNotBlank(bo.getP5Content()), BsRule::getP5Content, bo.getP5Content());
        lqw.eq(StringUtils.isNotBlank(bo.getP6Type()), BsRule::getP6Type, bo.getP6Type());
        lqw.eq(StringUtils.isNotBlank(bo.getP6Content()), BsRule::getP6Content, bo.getP6Content());
        return lqw;
    }

    /**
     * 新增编号规则设置
     */
    @Override
    public Boolean insertByBo(BsRuleBo bo) {
//        if (ObjectUtils.isNotEmpty(bo.getTableData())) {
//            int size = bo.getTableData().size();
//            List<Map> tableData = bo.getTableData();
//            switch (size) {
//                case 1:
//                    bo.setP1Type(tableData.get(0).get("pType").toString());
//                    bo.setP1Content(tableData.get(0).get("pContent").toString());
//                    break;
//                case 2:
//                    bo.setP1Type(tableData.get(0).get("pType").toString());
//                    bo.setP1Content(tableData.get(0).get("pContent").toString());
//                    bo.setP2Type(tableData.get(1).get("pType").toString());
//                    bo.setP2Content(tableData.get(1).get("pContent").toString());
//                    break;
//                case 3:
//                    bo.setP1Type(tableData.get(0).get("pType").toString());
//                    bo.setP1Content(tableData.get(0).get("pContent").toString());
//                    bo.setP2Type(tableData.get(1).get("pType").toString());
//                    bo.setP2Content(tableData.get(1).get("pContent").toString());
//                    bo.setP3Type(tableData.get(2).get("pType").toString());
//                    bo.setP3Content(tableData.get(2).get("pContent").toString());
//                    break;
//                case 4:
//                    bo.setP1Type(tableData.get(0).get("pType").toString());
//                    bo.setP1Content(tableData.get(0).get("pContent").toString());
//                    bo.setP2Type(tableData.get(1).get("pType").toString());
//                    bo.setP2Content(tableData.get(1).get("pContent").toString());
//                    bo.setP3Type(tableData.get(2).get("pType").toString());
//                    bo.setP3Content(tableData.get(2).get("pContent").toString());
//                    bo.setP4Type(tableData.get(3).get("pType").toString());
//                    bo.setP4Content(tableData.get(3).get("pContent").toString());
//                    break;
//                case 5:
//                    bo.setP1Type(tableData.get(0).get("pType").toString());
//                    bo.setP1Content(tableData.get(0).get("pContent").toString());
//                    bo.setP2Type(tableData.get(1).get("pType").toString());
//                    bo.setP2Content(tableData.get(1).get("pContent").toString());
//                    bo.setP3Type(tableData.get(2).get("pType").toString());
//                    bo.setP3Content(tableData.get(2).get("pContent").toString());
//                    bo.setP4Type(tableData.get(3).get("pType").toString());
//                    bo.setP4Content(tableData.get(3).get("pContent").toString());
//                    bo.setP5Type(tableData.get(4).get("pType").toString());
//                    bo.setP5Content(tableData.get(4).get("pContent").toString());
//                    break;
//                case 6:
//                    bo.setP1Type(tableData.get(0).get("pType").toString());
//                    bo.setP1Content(tableData.get(0).get("pContent").toString());
//                    bo.setP2Type(tableData.get(1).get("pType").toString());
//                    bo.setP2Content(tableData.get(1).get("pContent").toString());
//                    bo.setP3Type(tableData.get(2).get("pType").toString());
//                    bo.setP3Content(tableData.get(2).get("pContent").toString());
//                    bo.setP4Type(tableData.get(3).get("pType").toString());
//                    bo.setP4Content(tableData.get(3).get("pContent").toString());
//                    bo.setP5Type(tableData.get(4).get("pType").toString());
//                    bo.setP5Content(tableData.get(4).get("pContent").toString());
//                    bo.setP6Type(tableData.get(5).get("pType").toString());
//                    bo.setP6Content(tableData.get(5).get("pContent").toString());
//                    break;
//            }
//        }
        BsRule add = BeanUtil.toBean(bo, BsRule.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setRuleId(add.getRuleId());
        }
        return flag;
    }

    /**
     * 修改编号规则设置
     */
    @Override
    public Boolean updateByBo(BsRuleBo bo) {
        BsRule update = BeanUtil.toBean(bo, BsRule.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(BsRule entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除编号规则设置
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public BsRuleVo getRule(BsRuleBo bo) {
        LambdaQueryWrapper<BsRule> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtils.isNotEmpty(bo.getDeptId()), BsRule::getDeptId, bo.getDeptId());
        lqw.eq(ObjectUtils.isNotEmpty(bo.getSyTypeId()), BsRule::getSyTypeId, bo.getSyTypeId());
        BsRuleVo data = baseMapper.selectVoOne(lqw);
        return data;
    }

    /**
     * 根据试验室和试验类型获取对应的编号规则示例
     *
     * @param bo
     * @return
     */
    @Override
    public BsRuleVo getRuleSl(BsRuleBo bo) {
        LambdaQueryWrapper<BsRule> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtils.isNotEmpty(bo.getDeptId()), BsRule::getDeptId, bo.getDeptId());
        lqw.eq(ObjectUtils.isNotEmpty(bo.getSyTypeId()), BsRule::getSyTypeId, bo.getSyTypeId());
        BsRuleVo vo = baseMapper.selectVoOne(lqw);
        if (ObjectUtils.isEmpty(vo)) {
            return new BsRuleVo();
        }

        // 获取分隔符
        String fgf = ObjectUtils.isNotEmpty(iSysDictDataService.selectDictLabel("fgf", vo.getFgf()))?iSysDictDataService.selectDictLabel("fgf", vo.getFgf()):"";
        // 拼接编号
        String res = "";
        if (ObjectUtils.isNotEmpty(vo.getP1Content())) {
            res += vo.getP1Content() + fgf;
        }
        if (ObjectUtils.isNotEmpty(vo.getP2Content())) {
            res += vo.getP1Content() + fgf;
        }
        if (ObjectUtils.isNotEmpty(vo.getP3Content())) {
            res += vo.getP1Content() + fgf;
        }
        if (ObjectUtils.isNotEmpty(vo.getP4Content())) {
            res += vo.getP1Content() + fgf;
        }
        if (ObjectUtils.isNotEmpty(vo.getP5Content())) {
            res += vo.getP1Content() + fgf;
        }
        if (ObjectUtils.isNotEmpty(vo.getP6Content())) {
            res += vo.getP1Content();
        }
        String ypSl = res.replace("YP/JL/BG", "YP");
        String jlSl = res.replace("YP/JL/BG", "JL");
        String bgSl = res.replace("YP/JL/BG", "BG");

        List<String> ruleSls = new ArrayList<>();
        ruleSls.add(ypSl);
        ruleSls.add(jlSl);
        ruleSls.add(bgSl);

        return vo;
    }

    /**
     * 根据编号规则生成编号
     *
     * @param bo
     * @return
     */
    @Override
    public BsRuleVo getRuleRes(BsRuleBo bo) {
        LambdaQueryWrapper<BsRule> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtils.isNotEmpty(bo.getDeptId()), BsRule::getDeptId, bo.getDeptId());
//        lqw.eq(ObjectUtils.isNotEmpty(bo.getSyTypeId()), BsRule::getSyTypeId, bo.getSyTypeId());
        BsRuleVo vo = baseMapper.selectVoOne(lqw);
        if (ObjectUtils.isEmpty(vo)) {
            throw new ServiceException("获取编号失败，请先维护编号规则！");
        }
        // 获取分隔符
        String fgf = ObjectUtils.isNotEmpty(iSysDictDataService.selectDictLabel("fgf", vo.getFgf()))?iSysDictDataService.selectDictLabel("fgf", vo.getFgf()):"";

        // 拼接编号
        String res = "";
        if (ObjectUtils.isNotEmpty(vo.getP1Type()) && ObjectUtils.isNotEmpty(vo.getP1Content())) {
            if (StringUtils.isNotBlank(getSysDateByDict(vo.getP1Type()))) {
                res += getSysDateByDict(vo.getP1Type()) + fgf;
            } else if (StringUtils.isNotBlank(getIdentification(vo.getP1Type(), bo.getSyTypeId()))){
                res += getIdentification(vo.getP1Type(), bo.getSyTypeId()) + fgf;
            } else if (StringUtils.isNotBlank(getLsh(vo.getP1Type(), bo.getSyTypeId(), bo.getDeptId()))){
                res += getLsh(vo.getP1Type(), bo.getSyTypeId(), bo.getDeptId()) + fgf;
            } else {
                res += vo.getP1Content() + fgf;
            }
        }
        if (ObjectUtils.isNotEmpty(vo.getP2Type()) && ObjectUtils.isNotEmpty(vo.getP2Content())) {
            if (StringUtils.isNotBlank(getSysDateByDict(vo.getP2Type()))) {
                res += getSysDateByDict(vo.getP2Type()) + fgf;
            } else if (StringUtils.isNotBlank(getIdentification(vo.getP2Type(), bo.getSyTypeId()))){
                res += getIdentification(vo.getP2Type(), bo.getSyTypeId()) + fgf;
            } else if (StringUtils.isNotBlank(getLsh(vo.getP2Type(), bo.getSyTypeId(), bo.getDeptId()))){
                res += getLsh(vo.getP2Type(), bo.getSyTypeId(), bo.getDeptId()) + fgf;
            } else {
                res += vo.getP2Content() + fgf;
            }
        }
        if (ObjectUtils.isNotEmpty(vo.getP3Type()) && ObjectUtils.isNotEmpty(vo.getP3Content())) {
            if (StringUtils.isNotBlank(getSysDateByDict(vo.getP3Type()))) {
                res += getSysDateByDict(vo.getP3Type()) + fgf;
            } else if (StringUtils.isNotBlank(getIdentification(vo.getP3Type(), bo.getSyTypeId()))){
                res += getIdentification(vo.getP3Type(), bo.getSyTypeId()) + fgf;
            } else if (StringUtils.isNotBlank(getLsh(vo.getP3Type(), bo.getSyTypeId(), bo.getDeptId()))){
                res += getLsh(vo.getP3Type(), bo.getSyTypeId(), bo.getDeptId()) + fgf;
            } else {
                res += vo.getP3Content() + fgf;
            }
        }
        if (ObjectUtils.isNotEmpty(vo.getP4Type()) && ObjectUtils.isNotEmpty(vo.getP4Content())) {
            if (StringUtils.isNotBlank(getSysDateByDict(vo.getP4Type()))) {
                res += getSysDateByDict(vo.getP4Type()) + fgf;
            } else if (StringUtils.isNotBlank(getIdentification(vo.getP4Type(), bo.getSyTypeId()))){
                res += getIdentification(vo.getP4Type(), bo.getSyTypeId()) + fgf;
            } else if (StringUtils.isNotBlank(getLsh(vo.getP4Type(), bo.getSyTypeId(), bo.getDeptId()))){
                res += getLsh(vo.getP4Type(), bo.getSyTypeId(), bo.getDeptId()) + fgf;
            } else {
                res += vo.getP4Content() + fgf;
            }
        }
        if (ObjectUtils.isNotEmpty(vo.getP5Type()) && ObjectUtils.isNotEmpty(vo.getP5Content())) {
            if (StringUtils.isNotBlank(getSysDateByDict(vo.getP5Type()))) {
                res += getSysDateByDict(vo.getP5Type()) + fgf;
            } else if (StringUtils.isNotBlank(getIdentification(vo.getP5Type(), bo.getSyTypeId()))){
                res += getIdentification(vo.getP5Type(), bo.getSyTypeId()) + fgf;
            } else if (StringUtils.isNotBlank(getLsh(vo.getP5Type(), bo.getSyTypeId(), bo.getDeptId()))){
                res += getLsh(vo.getP5Type(), bo.getSyTypeId(), bo.getDeptId()) + fgf;
            } else {
                res += vo.getP5Content() + fgf;
            }
        }
        if (ObjectUtils.isNotEmpty(vo.getP6Type()) && ObjectUtils.isNotEmpty(vo.getP6Content())) {
            if (StringUtils.isNotBlank(getSysDateByDict(vo.getP6Type()))) {
                res += getSysDateByDict(vo.getP6Type()) + fgf;
            } else if (StringUtils.isNotBlank(getIdentification(vo.getP6Type(), bo.getSyTypeId()))){
                res += getIdentification(vo.getP6Type(), bo.getSyTypeId()) + fgf;
            } else if (StringUtils.isNotBlank(getLsh(vo.getP6Type(), bo.getSyTypeId(), bo.getDeptId()))){
                res += getLsh(vo.getP6Type(), bo.getSyTypeId(), bo.getDeptId()) + fgf;
            } else {
                res += vo.getP6Content() + fgf;
            }
        }

        res = res.substring(0, res.length()-1);

        String ypCode = res.replace("YP/JL/BG", "YP");
        String jlCode = res.replace("YP/JL/BG", "JL");
        String bgCode = res.replace("YP/JL/BG", "BG");

        vo.setBgCode(bgCode);
        vo.setYpCode(ypCode);
        vo.setJlCode(jlCode);

        return vo;
    }

    /**
     * 年月处理
     * @param type
     * @return
     */
    public String getSysDateByDict(String type) {
        LocalDate now = LocalDate.now();
        String year = String.valueOf(now.getYear());
        String month = (now.getMonthValue() >= 10) ? String.valueOf(now.getMonthValue()) : ("0" + now.getMonthValue());
        String res = "";
        switch (type) {
            case "0100": // 年份
                res = year;
                break;
            case "0101": // 年月
                res = year + month;
                break;
            case "0102": // 月年
                res = month + year ;
                break;
        }
        return res;
    }

    /**
     * 试验标识处理
     * @param type
     * @param syTypeId
     * @return
     */
    public String getIdentification(String type, Long syTypeId) {
        String res = "";
        if ("36".equals(type)) {
            // 根据试验类型获取对应的试验标识
            SyTypeVo vo = iSyTypeService.queryById(syTypeId);
            res = vo.getIdentification();
        }
        return res;
    }

    /**
     * 流水号处理
     * 流水号生成规则: 按照年月,区分试验类型
     *      例如: 土工 202405-001,202406-001 集料 202306-001,202406-001 ...
     * @param type
     * @param syTypeId
     * @param deptId
     * @return
     */
    public String getLsh(String type, Long syTypeId, Long deptId) {
        String res = "";
        if ("0201".equals(type) || "0200".equals(type)) {
            // 查询系统本年月的试验类型的数据报告数量
            Integer num = bsDataReportMapper.selectListNumBySysdate(syTypeId, deptId);
            String lsh = "1";
            switch (type) {
                case "0201": // 自增流水三位
                    lsh = String.valueOf(num+1);
                    res = (num!=null && num<10)? "00" + lsh : "0" + lsh;
                    break;
                case "0200": // 自增流水四位
                    lsh = String.valueOf(num+1);
                    res = (num!=null && num<10)? "000" + lsh : "00" + lsh;
                    break;
            }
        }
        return res;
    }

}
